package streaming.test;

import java.io.IOException;
import java.net.Inet4Address;

import javax.media.CannotRealizeException;
import javax.media.ControllerEvent;
import javax.media.ControllerListener;
import javax.media.DataSink;
import javax.media.Format;
import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.NoPlayerException;
import javax.media.NoProcessorException;
import javax.media.NotRealizedError;
import javax.media.Processor;
import javax.media.ProcessorModel;
import javax.media.datasink.DataSinkEvent;
import javax.media.datasink.DataSinkListener;
import javax.media.datasink.EndOfStreamEvent;
import javax.media.format.AudioFormat;
import javax.media.format.UnsupportedFormatException;
import javax.media.format.VideoFormat;
import javax.media.protocol.ContentDescriptor;
import javax.media.rtp.InvalidSessionAddressException;
import javax.media.rtp.RTPManager;
import javax.media.rtp.RemoteListener;
import javax.media.rtp.SendStream;
import javax.media.rtp.SendStreamListener;
import javax.media.rtp.SessionAddress;
import javax.media.rtp.SessionListener;
import javax.media.rtp.event.RemoteEvent;
import javax.media.rtp.event.SendStreamEvent;
import javax.media.rtp.event.SessionEvent;

import com.sun.media.rtp.RTPSessionMgr;

public class Sender implements ControllerListener, DataSinkListener, SessionListener, RemoteListener, SendStreamListener{


	Processor processor, audioProcessor;
	AudioFormat RTPformatAudio = new AudioFormat(AudioFormat.GSM_RTP);
	VideoFormat RTPformatVideo = new VideoFormat(VideoFormat.H263_RTP);
	AudioFormat formatAudio = new AudioFormat(AudioFormat.LINEAR);
	VideoFormat formatVideo = new VideoFormat(VideoFormat.RGB);
	private MediaLocator audioLocator, videoLocator;
	private RTPManager audioManager, videoManager;


	DataSink sink, audioSink;

	public Sender(String url){
		this.audioLocator = new MediaLocator("rtp://"+url+":"+22222+"/audio");
		this.videoLocator = new MediaLocator("rtp://"+url+":"+22224+"/video");


		try {
			processor = Manager.createRealizedProcessor(
					new ProcessorModel(
							new Format[]{/*formatAudio,*/ RTPformatVideo},
							new ContentDescriptor(ContentDescriptor.RAW_RTP)));


			sink = Manager.createDataSink(processor.getDataOutput(), videoLocator);
			sink.addDataSinkListener(this);
			processor.start();
			sink.open();
			sink.start();
		}
		catch(Exception e){
			System.out.println("video not initialized");
		}

//		} catch (NoDataSinkException ex) {
//		// TODO Auto-generated catch block
//		ex.printStackTrace();
//		} catch (SecurityException ex) {
//		// TODO Auto-generated catch block
//		ex.printStackTrace();
//		} catch (IOException ex) {
//		// TODO Auto-generated catch block
//		ex.printStackTrace();
//		} catch (NoProcessorException e) {
//		System.out.println("Unable to find specified processor");
//		e.printStackTrace();
//		} catch (CannotRealizeException e) {
//		// TODO Auto-generated catch block
//		e.printStackTrace();
//		} catch (NotRealizedError e) {
//		// TODO Auto-generated catch block
//		e.printStackTrace();
//		}

		try {
			audioProcessor = Manager.createRealizedProcessor(
					new ProcessorModel(
							new Format[]{/*formatAudio,*/ RTPformatAudio},
							new ContentDescriptor(ContentDescriptor.RAW_RTP)));

			audioSink = Manager.createDataSink(audioProcessor.getDataOutput(), audioLocator);
			audioSink.addDataSinkListener(this);
			audioProcessor.start();
			audioSink.open();
			audioSink.start();
		}
		catch(Exception e){
			System.out.println("audio not initialized");
		}
//		} catch (NoProcessorException e) {
//		// TODO Auto-generated catch block
//		e.printStackTrace();
//		} catch (CannotRealizeException e) {
//		// TODO Auto-generated catch block
//		e.printStackTrace();
//		} catch (IOException e) {
//		// TODO Auto-generated catch block
//		e.printStackTrace();
//		} catch (NoDataSinkException e) {
//		// TODO Auto-generated catch block
//		e.printStackTrace();
//		} catch (NotRealizedError e) {
//		// TODO Auto-generated catch block
//		e.printStackTrace();
//		}


		System.out.println("Sending to address " + url);
	}

	public Sender(String url, boolean session){
//		this.locator = locator;


		try {
			processor = Manager.createRealizedProcessor(
					new ProcessorModel(
							new Format[]{/*formatAudio,*/ RTPformatVideo},
							new ContentDescriptor(ContentDescriptor.RAW_RTP)));

			videoManager = RTPSessionMgr.newInstance();
			videoManager.initialize(new SessionAddress());
			videoManager.addTarget(
					new SessionAddress(
							Inet4Address.getByName(
									url),
									22222
					));
			videoManager.addSendStreamListener(this);
			videoManager.addSessionListener(this);
			videoManager.addRemoteListener(this);
			SendStream stream = videoManager.createSendStream(processor.getDataOutput(), 0);

			processor.start();
			stream.start();
		} catch (Exception ex) {
			ex.printStackTrace();
		}

		
		try {
			audioProcessor = Manager.createRealizedProcessor(
					new ProcessorModel(
							new Format[]{/*formatAudio,*/ RTPformatAudio},
							new ContentDescriptor(ContentDescriptor.RAW_RTP)));

			audioManager = RTPSessionMgr.newInstance();
			audioManager.initialize(new SessionAddress());
			audioManager.addTarget(
					new SessionAddress(
							Inet4Address.getByName(
									url),
									22224
					));
			audioManager.addSendStreamListener(this);
			audioManager.addSessionListener(this);
			audioManager.addRemoteListener(this);
			SendStream stream = audioManager.createSendStream(audioProcessor.getDataOutput(), 0);

			audioProcessor.start();
			stream.start();
		} catch (Exception ex) {
			ex.printStackTrace();
		}


	}

	public static void main(String[] args) {
//		new Sender();
	}

	@Override
	public void controllerUpdate(ControllerEvent e) {


	}

	@Override
	public void dataSinkUpdate(DataSinkEvent e) {

		if( e instanceof EndOfStreamEvent){
			sink.close();
			processor.close();
			audioSink.close();
			audioProcessor.close();
		}
		System.out.println(e);
	}


	public void start(){
		try {

			if(processor != null && processor.getState() == Processor.Realized){
				sink.start();
			}
			if(audioProcessor != null && audioProcessor.getState() == Processor.Realized){
				audioSink.start();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void pause(){
		processor.stop();
		audioProcessor.stop();
		try {
			sink.stop();
			audioSink.stop();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}


	public void stop(){
		System.out.println("stopping");
		try {
			if(processor != null && processor.getState() == processor.Started){
				processor.stop();
				sink.stop();
				processor.close();
				sink.close();
			}
			if(audioProcessor != null && audioProcessor.getState() == processor.Started){
				audioProcessor.stop();
				audioSink.stop();
				audioProcessor.close();
				audioSink.close();
			}

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public void update(SessionEvent e) {
		// TODO Auto-generated method stub
		System.out.println(e.toString());
	}

	@Override
	public void update(RemoteEvent e) {
		// TODO Auto-generated method stub
		System.out.println(e.toString());
	}

	@Override
	public void update(SendStreamEvent e) {
		// TODO Auto-generated method stub
		System.out.println(e.toString());
	}

}



